package com.shuiyun.jtt.handler;

import com.shuiyun.jtt.anno.Message;
import com.shuiyun.jtt.message.Header;
import com.shuiyun.jtt.message.JTMessage;
import com.shuiyun.jtt.session.Session;
import lombok.Data;
import org.springframework.context.ApplicationContext;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

import java.lang.reflect.Method;
import java.lang.reflect.Type;

/**
 * @author shuiyun
 * @program gateway
 * @description 反射处理类
 * @date 2022-04-20 10:23
 **/
@Data
@SuppressWarnings("unchecked")
public class Handler {

    public static final int MESSAGE = 0;
    public static final int SESSION = 1;
    public static final int HEADER = 2;

    /**
     * 目标类
     */
    private final Class targetObject;
    /**
     * 目标方法
     */
    private final Method targetMethod;
    /**
     * 目标方法描述
     */
    public final String desc;

    /**
     * 目标方法是否是无返回方法 void 为无结果返回方法
     */
    public final boolean returnVoid;

    private final int[] parameterTypes;

    public Handler(Class<?> targetObject, Method targetMethod, String desc) {
        this.targetObject = targetObject;
        this.targetMethod = targetMethod;
        this.desc = desc;
        this.returnVoid = targetMethod.getReturnType().isAssignableFrom(Void.TYPE);
        // 把参数位置信息记录下来 eg:如果最后参数记录数据是 210 则请求参数顺序是 HEADER SESSION MESSAGE
        this.parameterTypes = getParameterIndex(targetMethod);
    }

    /**
     * 单设调用
     *
     * @param request 请求消息
     * @return 方法调用结果
     * @author shuiyun
     * @date 2022-04-20 11:30
     */
    public <T extends JTMessage> T invoke(T request, Session session, ApplicationContext context) throws Exception {
        Object[] args = getParameters(request, session);
        try {
            Object target = context.getBean(targetObject);
            return (T) targetMethod.invoke(target, args);
        } catch (Exception e) {
            throw new RuntimeException(desc + " 执行失败：" + e.getMessage());
        }
    }


    /**
     * 获取请求参数
     *
     * @param request 请求消息
     * @param session 缓存信息
     * @return 请求参数
     * @author shuiyun
     * @date 2022-04-20 10:56
     */
    private <T extends JTMessage> Object[] getParameters(T request, Session session) {
        // 请求参数
        Object[] args = new Object[parameterTypes.length];

        for (int i = 0; i < parameterTypes.length; i++) {
            int type = parameterTypes[i];
            switch (type) {
                case MESSAGE:
                    args[i] = request;
                    break;
                case SESSION:
                    args[i] = session;
                    break;
                case HEADER:
                    args[i] = request.getHeader();
                    break;
                default:
                    break;
            }
        }
        return args;
    }


    /**
     * 获取参数位置坐标信息
     *
     * @param targetMethod 请求方法
     * @return 参数坐标信息
     * @author shuiyun
     * @date 2022-04-20 10:49
     */
    private int[] getParameterIndex(Method targetMethod) {
        Type[] types = targetMethod.getGenericParameterTypes();
        int[] parameterTypes = new int[types.length];
        for (int i = 0; i < types.length; i++) {
            Type type = types[i];

            Class clazz = null;
            if (type instanceof ParameterizedTypeImpl) {
                clazz = (Class<?>) ((ParameterizedTypeImpl) type).getActualTypeArguments()[0];
            } else {
                clazz = (Class<?>) type;
            }

            // 按照参数类型 判断请求方法每个参数的位置
            if (Message.class.isAssignableFrom(clazz)) {
                parameterTypes[i] = MESSAGE;
            } else if (Header.class.isAssignableFrom(clazz)) {
                parameterTypes[i] = HEADER;
            } else if (Session.class.isAssignableFrom(clazz)) {
                parameterTypes[i] = SESSION;
            }
        }
        return parameterTypes;
    }
}
